package com.gc.ip;

import java.io.IOException;
import java.util.Iterator;
import java.util.StringTokenizer;
import java.util.Vector;
import java.awt.Font;
import java.awt.GraphicsEnvironment;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.ClipboardOwner;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.JTextField;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

import javax.swing.JOptionPane;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

//pick up from IPField
public class JIPv4TextField extends JTextField implements ClipboardOwner, FocusListener
{
	private static final long serialVersionUID = -2480103797779739206L;
	private Vector<Integer> delims = new Vector<Integer>();
    private StringBuffer text;

    //Property change support
    public static final String VALUE = "value";
    private PropertyChangeSupport pcs = null;
    
    /**
     *
     * Constructor MaskedField
     *
     * @param format
     *
     * @param delimeter
     *
     *
     *
     */
    public static final int IPv4 = 0;

    /**
     * @param value - does not do anything, it's because the old IPField wanted such a parameter
     */
    public JIPv4TextField(int value)
    { 
        this();
    }

    public JIPv4TextField()
    {

        this("0000.00000.00000.0000", new char[]
             {'.'});

    }

    /**
     *
     * Constructor MaskedField
     *
     * @param format
     *
     * @param delimeters
     *
     *
     *
     */

    private JIPv4TextField(String format, char[] delimeters)
    {

        super(format.length() + 1);

        // do not use default focus traversal key (TAB and SHIFT-TAB)
        // component has own implementation

        // replaces deprecated isManagingFocus()
//      cq200024295: make focus work normally, special behaviour only commented out for now
//        setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
//                              java.util.Collections.EMPTY_SET);
//        setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
//                              java.util.Collections.EMPTY_SET);

        addFocusListener(this);

//        setFont(new Font("Courier", Font.PLAIN, 11));
        //Check if the required font exist before setting
        setDefaultFont();

        text = new StringBuffer(format.length());

        for (int i = 0; i < format.length(); i++)
        {

            char currentChar = ' ';

            for (int j = 0; j < delimeters.length; j++)
            {

                if (format.charAt(i) == delimeters[j])
                {

                    delims.addElement(new Integer(i));

                    currentChar = format.charAt(i);

                }

            }

            text.append(currentChar);

        }

        addKeyListener(new MaskedFieldListener());
        addMouseListener( new MouseAdapter() {
            @Override
            public void mouseClicked( MouseEvent e )
            {
                // place caret correctly if user clicks on empty space
                // when the click is on text, do nothing
                int pos = getCaretPosition();
                int lastDecimalPos = jumpLastPos(pos);
                int blockStart = lastDecimalPos == 0 ? 0 : lastDecimalPos + 2;
                int nextDecimalPos = jumpNextPos(pos); // get value block end position
                if (nextDecimalPos < text.length())
                    nextDecimalPos--;  // correct middle block ending

                if ( pos == 0 ||
                     (pos > lastDecimalPos
                      && pos <= blockStart) )
                {
                    // user clicked at the start of the block
                    setCaretPosition(blockStart);
                }
                else
                {
                    // make sure caret is at the end of current block text
                    // or if block is empty, at the beginning of block
                    String value = text.substring(blockStart, nextDecimalPos);
                    value = value.trim();
                    int len = value.length();

                    // if click is on empty space after, move caret
                    if ( pos > blockStart + len )
                    {
                        setCaretPosition(blockStart + len);
                    }
                    // otherwise the user clicked on existing text --> do nothing
                }
            }
        });
        this.getDocument().addDocumentListener(new ParseIPDocumentListener());

        super.setText(text.toString());
        setCaretPosition(0);  // initialize caret position for focus handling

    }
    
    private void setDefaultFont()
    {
    	String[] targetFontNames = {"Courier", "Courier New", "Monospaced"};
    	
    	String[] families = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
    	for(String familyName : families)
		{
    		for(String targetName : targetFontNames)
    		{
    			if(targetName.equals(familyName))
    			{
    				setFont(new Font(targetName, Font.PLAIN, 11));
    				return;
    			}
    		}
		}
    }

    @Override
    public void copy()
    {

        Clipboard clipboard = getToolkit().getSystemClipboard();

        String selectedText = getSelectedText();

        StringTokenizer tokens = new StringTokenizer(selectedText, ".");
        String ip = "";
        while (tokens.hasMoreElements())
        {
            String token = tokens.nextToken().trim();
            if (ip.length() > 0)
            {
                ip = ip + '.';
            }
            ip = ip + token;
        }

        StringSelection tranferable = new StringSelection(ip);

        clipboard.setContents(tranferable, this);

        //System.out.println("CONTENT IN THE CLIPBOARD " + ip);

    }

    public void lostOwnership(Clipboard clipboard, Transferable contents)
    {
        //does nothing at the moment
    }

    public void focusGained(FocusEvent e)
    {
        // cq200025987 : first item
        // if clicked block is empty, move caret to the beginning of that block
        int pos = getCaretPosition();
        if (isEmpty( pos ))
        {
            setCaretPosition( pos == 0 ? 0 : jumpLastPos(pos) + 2 );
        }
        else
        {
            // cq200024295
            // select correct octet: if we arrive via TAB-key caretPosition is 0
            // if via mouse click, caret position is the place that was clicked
            selectNextBlock(pos); // was 0
        }
    }

    public void focusLost(FocusEvent e)
    {
        // cq200024295, reset caret position when losing focus
        // in preparation for next keyboard focus arrival
        setCaretPosition(0);
    }

    @Override
    public void paste()
    {

        Clipboard clipboard = getToolkit().getSystemClipboard();

        Transferable transferable =
            clipboard.getContents(DataFlavor.stringFlavor);

        Object pasteValue = null;

        try
        {

            pasteValue = transferable.getTransferData(DataFlavor.stringFlavor);

        }
        catch (UnsupportedFlavorException e)
        {

            return;

        }
        catch (IOException e)
        {

            return;

        }

        if (isLegalPaste( (String) pasteValue))
        {

            String paste = (String) pasteValue;
            setIp(paste);
        }
        else
        {
            //say paste is not possible
            JOptionPane.showMessageDialog(javax.swing.FocusManager.getCurrentManager().getFocusedWindow(),
                                          "Not legal IP address paste: " + (String) pasteValue,
                                          "IP Address Field",
                                          JOptionPane.ERROR_MESSAGE);
        }

    }

    private boolean isLegalPaste(String paste)
    {
        StringTokenizer tokens = new StringTokenizer(paste, ".");

//        int blocksLeft = 1; //there is always at least one block
//
//        for (Iterator i = delims.iterator(); i.hasNext(); )
//        {
//            int separator = ( (Integer) i.next()).intValue();
//            if (separator >= this.getCaretPosition())
//            {
//                blocksLeft++;
//            }
//        }
//
//        if (tokens.countTokens() > blocksLeft)
//        {
//            System.out.println(
//                "not blocks left " + blocksLeft + " " + tokens.countTokens());
//            return false;
//        }

        if (tokens.countTokens() != 4)
        {
            System.out.println(
                "Not a valid IP paste:" + paste);
            return false;
        }


        while (tokens.hasMoreTokens())
        {
            String token = (tokens.nextToken());
            int value;
            try
            {
                value = Integer.parseInt(token.trim());
            }
            catch (NumberFormatException e)
            {
                e.printStackTrace();
                return false;
            }
            if (value > 255 || value < 0)
            {
                System.out.println(" value " + value);
                return false;
            }
        }
        return true;
    }

    public void selectNextBlock(int caret)
    {
        int lastDecimalPos = 0;
        int nextDecimalPos = text.length();
        for (Iterator<Integer> i = delims.iterator(); i.hasNext(); )
        {
            int x = i.next().intValue();

            if (x < caret)
            {
                lastDecimalPos = x;

            }
            if (x > caret)
            {

                nextDecimalPos = x;

                break;

            }

        }
        while (lastDecimalPos != text.length()
               && (text.charAt(lastDecimalPos) == ' '
                   || text.charAt(lastDecimalPos) == '.'))
        {
            lastDecimalPos++;
        }
        while (text.charAt(nextDecimalPos - 1) == ' '
               && nextDecimalPos > lastDecimalPos)
        {
            nextDecimalPos--;
        }
        if (nextDecimalPos > lastDecimalPos)
        {
            select(lastDecimalPos, nextDecimalPos);
        }
        repaint();
    }

    /**
     * Set's an ip to the field, must in format: "XXX.XXX.XXX.XXX"
     *
     * @param ip
     */
    public void setIp(final String ip)
    {
        if (ip == null || ip.equals(""))
        {
            clear();
            return;
        }
        
        final String oldText = text.toString();
        final String[] tokens = ip.replaceAll(" ", "").split("\\.");
        int start = 0;
        int token = 0;
        for (final Iterator<Integer> i = delims.iterator(); i.hasNext();)
        {
            final int end = i.next().intValue();
            String sub = token < tokens.length ? tokens[token] : "   ";
            while (sub.length() < 3)
            {
                sub += " ";
            }
            text.replace(start, end-1, sub);
            start = end + 2;
            token++;
        }
        
        String sub = token < tokens.length ? tokens[token] : "   ";
        while (sub.length() < 3)
        {
            sub += " ";
        }
        text.replace(start, text.length(), sub);
        
        super.setText(text.toString());
        getPcs().firePropertyChange(JIPv4TextField.VALUE, oldText, text.toString());
        setCaretPosition(0); // reset caret position for focus handling
    }

    @Override
    public void setText(String txt)
    {
        setIp(txt);
    }

    public void superSetText(final String txt)
    {
        final String oldText = super.getText();
        //to be used from inner class
        super.setText(txt);
        getPcs().firePropertyChange(JIPv4TextField.VALUE, oldText, txt);
    }

    /**
     * Return the ip value in the field in format: "XXX.XXX.XXX.XXX"
     *
     * @return
     */
    public String getIp()
    {
        //laita 0:t blokkeihin jossa ei ole mit��n
        StringBuffer changedText = new StringBuffer(text.toString());
        int current = 0;
        for (Iterator<Integer> i = delims.iterator(); i.hasNext(); )
        { //goes through block 1-3
            int sep = i.next().intValue();
            String sub = changedText.substring(current, sep - 1);

            if (sub.replaceAll(" ", "").length() == 0)
            {
                sub = "0  ";
            }
            changedText.replace(current, sep - 1, replaceLeadingZerosWithSpaces(sub));
            current = sep + 2;
        }
        String sub = changedText.substring(current, changedText.length()); //checks the last block

        if (sub.replaceAll(" ", "").length() == 0)
        {
            sub = "0  ";
        }
        changedText.replace(current, text.length(), replaceLeadingZerosWithSpaces(sub));

        String ip = changedText.toString().replaceAll(" ", "");
        return ip;

    }

    /**
     * Replaces leading zeros with empty space <=> '.001' = '.  1' and '. 00' = '.  0' and '.100' = '.100'  
     * @param inputStr
     * @return
     */
    private String replaceLeadingZerosWithSpaces(String inputStr)
    {
        StringBuilder str = new StringBuilder();
        boolean changed = false;
        boolean firstDigit = true;
        for (int i = 0; i < inputStr.length(); i++)
        {
            char c = inputStr.charAt(i);
            if (c == '.')
            {
                firstDigit = true;
                str.append(c);
            }
            else if (firstDigit && c == '0' && i < inputStr.length()-1 && Character.isDigit(inputStr.charAt(i+1)))
            {
                // replace leading zeroes with spaces
                str.append(' ');
                changed = true;
            }
            else
            {
                if (Character.isDigit(c))
                {
                    firstDigit = false;
                }
                str.append(c);
            }
        }
        return changed ? str.toString() : inputStr; 
    }

    @Override
    public String getText()
    {
        return getIp();
    }

    public String superGetText()
    {
        return super.getText();
    }

    public void recursivelyAddFocusListener(FocusListener list)
    {
        addFocusListener(list);
    }

    public void clear()
    {
        for (int i = 0; i < text.length(); i++)
        {
            if (Character.isDigit(text.charAt(i)))
            {
                text.setCharAt(i, ' ');
            }
        }
        super.setText(text.toString());
    }

    /**
     * Returns current IP value coded as hexadecimal.
     *
     * @return IP value
     */
    public long getHexValue() throws Exception
    {
        StringBuffer value = new StringBuffer();
        StringBuffer temp = new StringBuffer();
        StringTokenizer tokens = new StringTokenizer(getIp(), ".");
        long bin = 0;
        int tempBlock = 0;

        while (tokens.hasMoreElements())
        {
            try
            {
                tempBlock = Integer.parseInt(tokens.nextToken());
            }
            catch (NumberFormatException nfe)
            {
                tempBlock = 0;
            }

            temp = new StringBuffer(Integer.toString(tempBlock, 16));
            if (temp.length() < 2)
            {
                temp.insert(0, '0');
            }

            value.append(temp.toString());
        }
        if (value.length() == 0)
        {
            value.append("0");

        }
        bin = Long.parseLong(value.toString(), 16);

        return bin;
    }

    private void correctString()
    { //removes wrong whitespaces from the whole string
        String[] blocks = new String[4];
        int block = 0;
        int current = 0;
        for (Iterator<Integer> i = delims.iterator(); i.hasNext(); )
        { //checks the first three blocks
            int sep = i.next().intValue();
            blocks[block] = text.substring(current, sep - 1);

            blocks[block] = removeWhitespaces(blocks[block]);

            text.replace(current, sep - 1, blocks[block]);
            //   System.out.println( blocks[block] + " " + blocks[block].length() );
            block++;
            current = sep + 2;
        }
        //checks the last block
        blocks[block] = text.substring(current, text.length());

        blocks[block] = removeWhitespaces(blocks[block]);

        text.replace(current, text.length(), blocks[block]);
    }

    private String removeWhitespaces(String block)
    {
        String result = block.replaceAll(" ", ""); //removing emptySpaces
        while (result.length() < 3)
        {
            result = result + " ";
        }
        return result;

    }

    class MaskedFieldListener extends KeyAdapter
    {

        private void insertWhitespace(int caretPos)
        {

            int nextPos = jumpNextPos(caretPos);

            if (nextPos == text.length())
            {

                text.insert(nextPos, " ");

            }
            else
            {

                text.insert(nextPos - 2, " ");

            }

        }

        /**
         *
         * Method keyPressed
         *
         * @param key
         *
         *
         *
         */

        @Override
        public void keyPressed(KeyEvent key)
        {

            int caretPos = getCaretPosition();

            if (getSelectedText() != null)
            {
                int selStart = getSelectionStart();
                //empty selected area (only from numbers)
                // cq200025987 : second item: add Backspace
                for (int i = selStart; i < getSelectionEnd(); i++)
                {
                    if (text.charAt(i) != ' '
                        && text.charAt(i) != '.'
                        &&
                        (Character.isDigit(key.getKeyChar()) ||
                         key.getKeyCode() == KeyEvent.VK_DELETE ||
                         key.getKeyCode() == KeyEvent.VK_BACK_SPACE))
                    {
                        text.setCharAt(i, ' ');
                    }
                }
                if (key.getKeyCode() == KeyEvent.VK_DELETE ||
                    key.getKeyCode() == KeyEvent.VK_BACK_SPACE)
                {
                    correctString();
                    key.consume();
                    superSetText(text.toString());
                    setCaretPosition(selStart);
                    return;
                }

                // get next valid input place
                switch (selStart)
                {
                    case 3:
                    case 4:
                    case 5:
                        caretPos = 6;
                        break;
                    case 9:
                    case 10:
                    case 11:
                        caretPos = 12;
                        break;
                    case 15:
                    case 16:
                    case 17:
                        caretPos = 18;
                        break;
                    default:
                        if (Character.isDigit(key.getKeyChar()))
                            caretPos = selStart;
                        break;
                }
            }
            boolean isDeleteValid = true;
            boolean isBackValid = true;
            boolean consume = true;

            for (int i = 0; i < delims.size(); i++)
            {

                int x = delims.elementAt(i).intValue();

                if (caretPos == x + 1 || caretPos == x || caretPos == x - 1)
                {

                    isDeleteValid = false;
                }

                if (caretPos == x + 2 || caretPos == x + 1 || caretPos == x)
                { //caretPos == x - 1?

                    isBackValid = false;
                }

            }

            switch (key.getKeyCode())
            {

                case (KeyEvent.VK_BACK_SPACE):

                    if (isBackValid && caretPos > 0)
                    {
                        text.deleteCharAt(caretPos - 1);
                        insertWhitespace(caretPos - 1);
                        caretPos--;
                    }
                    else if (!isBackValid && caretPos  > 0)
                    {
                        while (caretPos - 1 >= 0
                               && (text.charAt(caretPos - 1) == ' '
                                   || text.charAt(caretPos - 1) == '.'))
                        {
                            caretPos--;
                        }
                    }
                    break;

                case (KeyEvent.VK_DELETE):

                    if ( (caretPos <= text.length() - 1) && isDeleteValid && !isEmpty(caretPos) )
                    {
                        text.deleteCharAt(caretPos);
                        insertWhitespace(caretPos);
                    }
                    else if ( !isDeleteValid
                              && jumpNextPos(caretPos) != text.length() )
                    {
                        caretPos = jumpNextPos(caretPos) + 1;
                    }
                    else if ( !Character.isDigit(text.charAt(caretPos))
                              && isDeleteValid
                              && jumpNextPos(caretPos) != text.length() )
                    {
                        caretPos = jumpNextPos(caretPos) + 1;
                    }

                    break;

                case (KeyEvent.VK_LEFT):

                    if (isBackValid && caretPos > 0)
                    {

                        caretPos--;
                        while (caretPos - 1 >= 0
                               && !isDelimn(caretPos)
                               && (text.charAt(caretPos) == ' '
                                   || text.charAt(caretPos) == '.')
                               && (text.charAt(caretPos - 1) == ' '
                                   || text.charAt(caretPos - 1) == '.'))
                        {
                            caretPos--;
                        }

                    }
                    else if (caretPos - 3 > 0)
                    {

                        caretPos -= 3;
                        while (caretPos - 1 >= 0
                               && !isDelimn(caretPos)
                               && (text.charAt(caretPos) == ' '
                                   || text.charAt(caretPos) == '.')
                               && (text.charAt(caretPos - 1) == ' '
                                   || text.charAt(caretPos - 1) == '.'))
                        {
                            caretPos--;
                        }

                    }
                    key.consume();
                    setCaretPosition(caretPos);

                    return;

                case (KeyEvent.VK_RIGHT):

                    // if there is selection, just remove the selection highlight
                    // and do nothing else
                    if (isSelected( caretPos ))
                    {
                        setSelectionStart( caretPos );
                        setSelectionEnd( caretPos );
                        key.consume();
                        return;
                    }

                    if (isDeleteValid && caretPos < text.length())
                    {

                        caretPos++;

                        while (caretPos + 1 <= text.length()
                               && !isDelimn(caretPos)
                               && (text.charAt(caretPos) == ' '
                                   || text.charAt(caretPos) == '.')
                               && (text.charAt(caretPos - 1) == ' '
                                   || text.charAt(caretPos - 1) == '.'))
                        {
                            caretPos++;
                        }

                    }
                    else if (caretPos + 3 < text.length())
                    {

                        caretPos += 3;
                        while (caretPos + 1 <= text.length()
                               && !isDelimn(caretPos)
                               && (text.charAt(caretPos) == ' '
                                   || text.charAt(caretPos) == '.')
                               && (text.charAt(caretPos - 1) == ' '
                                   || text.charAt(caretPos - 1) == '.'))
                        {
                            caretPos++;
                        }

                    }
                    key.consume();
                    setCaretPosition(caretPos);

                    return;

//      cq200024295: make focus work normally, special behaviour only commented out for now
//                case (KeyEvent.VK_TAB):
//
//                	if (key.isShiftDown()) {
//                		caretPos = jumpLastPos(caretPos);
//                		if (caretPos == 0) {
//                			KeyboardFocusManager focusManager =
//                				KeyboardFocusManager
//								.getCurrentKeyboardFocusManager();
//
//                 			focusManager.focusPreviousComponent();
//
//                			key.consume();
//                			return;
//                		}
//                		caretPos = jumpLastPos(caretPos);
//                		if (caretPos != 0 ) caretPos += 2;
//
//                	} else {
//                		caretPos = jumpNextPos(caretPos);
//                		if (caretPos + 2 <= text.length())
//                		{
//
//                			caretPos++;
//
//                		}
//                		if (caretPos == text.length())
//                		{
//
//                			KeyboardFocusManager focusManager =
//                				KeyboardFocusManager
//								.getCurrentKeyboardFocusManager();
//
//                			focusManager.focusNextComponent();
//
//                			key.consume();
//                			return;
//                		}
//                	}
//
//                    if (consume)
//                    {
//                        key.consume();
//
//                    }
//                    superSetText(text.toString());
//
//                    setCaretPosition(caretPos);
//
//                    selectNextBlock(caretPos);
//
//                    return;

                case (KeyEvent.VK_CONTROL):

                    return;

                case (KeyEvent.VK_SHIFT):

                	return;

                case (KeyEvent.VK_C):

                    if (key.isControlDown())
                    {
                        return;
                    }
                    break;
//
//                case (KeyEvent.VK_ALT):
//
//                    return;
//
                case (KeyEvent.VK_V):

                    if (key.isControlDown())
                    {
                        return;
                    }
                    break;

                default:

                    if (key.getKeyChar() == '.')
                    {
                        if (isEmpty(caretPos) || isSelected(caretPos))
                        {
                            return;
                        }

                        caretPos = jumpNextPos(caretPos);

                        if (caretPos + 2 <= text.length())
                        {
                            caretPos++;
                            selectNextBlock(caretPos);
                        }

                        break;

                    }

                    if (Character.isDigit(key.getKeyChar()))
                    {

                        if (getSelectedText() != null)
                        {
                            setSelectionStart( caretPos );
                            setSelectionEnd( caretPos );
                        }

                        boolean addToCaret = true;

                        if ( (caretPos <= text.length() - 1) && isDeleteValid)
                        {
                            if (isMaxValue(caretPos, key))
                            {
                                text.setCharAt(caretPos, key.getKeyChar());
                                //laittaa numeron siihen caretin kohtaan miss�
                                // ollaan
                                caretPos = testCurrentValue(caretPos);
                            }
                            else
                            {
                                addToCaret = false;
                            }
                        }

                        if ( (caretPos <= text.length() - 3) && !isDeleteValid)
                        {
                            if (isMaxValue(caretPos, key))
                            {
                                text.setCharAt(caretPos + 3, key.getKeyChar());
                                //hypp�� pisteen yli ja asettaa mueroin siihen

                                caretPos = jumpNextPos(caretPos);
                            }
                            else
                            {
                                caretPos = jumpNextPos(caretPos);
                            }
                            selectNextBlock(caretPos);
                        }

                        if (caretPos <= text.length() - 1 && addToCaret)
                        {
                            caretPos += 1;
                        }
                        correctString();
                    }
                    else
                    {
                        // all not processed keyevents
                        // forward them to parent
                        // cq200026345
                        consume = false;
                    }
                    break;
            }

            if (consume)
            {
                key.consume();

            }
            // add selection if jumping to next block
            boolean doSelect = getSelectionEnd() > getSelectionStart();
            superSetText(text.toString());

            setCaretPosition(caretPos);
            if (doSelect)
            {
                selectNextBlock(caretPos);
            }
            else
            {
                // reset selection interval
                select(caretPos, caretPos);
            }
        }

        private boolean isDelimn(int caret)
        {
            for (Iterator<Integer> i = delims.iterator(); i.hasNext(); )
            {
                Integer dl = i.next();
                if (caret == dl.intValue() + 2)
                {
                    return true;
                }
            }
            return false;
        }

        /**
         *
         * Method keyTyped
         *
         * @param key
         *
         *
         *
         */

        @Override
        public void keyTyped(KeyEvent key)
        {

            key.consume();

        }

    }

    public int jumpNextPos(int caretPos)
    {

        int nextDecimalPos = 0;

        for (Iterator<Integer> i = delims.iterator(); i.hasNext(); )
        {

            int x = i.next().intValue();

            if (x >= caretPos)
            {

                nextDecimalPos = x;

                break;

            }

        }

        if (nextDecimalPos < caretPos)
        {

            return text.length();

        }

//        select(nextDecimalPos + 1, nextDecimalPos + 4);
//        setCaretPosition(nextDecimalPos + 1);
//        selectNextBlock(nextDecimalPos + 1);
        return nextDecimalPos + 1;

    }

    public int jumpLastPos(int caretPos)
	{

    	int lastDecimalPos = 0;

    	for (Iterator<Integer> i = delims.iterator(); i.hasNext();)
    	{

    		int x = i.next().intValue();

    		if (x < caretPos)
    		{

    			lastDecimalPos = x;

    		}

    	}

    	return lastDecimalPos;

    }

    private int testCurrentValue(int caretPos)
    {

        int lastDecimalPos = -1;

        int nextDecimalPos = 0;

        for (Iterator<Integer> i = delims.iterator(); i.hasNext(); )
        {

            int x = i.next().intValue();

            if (x <= caretPos)
            {
                lastDecimalPos = x;

            }
            if (x > caretPos)
            {

                nextDecimalPos = x;

                break;

            }

        }

        if (lastDecimalPos >= nextDecimalPos)
        {
            nextDecimalPos = text.length();

        }
        String value = text.substring(lastDecimalPos + 1, nextDecimalPos);

        value = value.trim();

        try
        {
            // if block has three numbers and caret is after the last one
            // if block has two or more numbers and <number> + 1  gt 255
            // if block has two or less numbers and "<number>1" gt 255
            // --> jump to next block
            if (( caretPos == nextDecimalPos - 2 && value.length() == 3)
                || (value.length() >= 2 && Integer.parseInt(value) + 1 > 255)
                || (value.length() <= 2 && Integer.parseInt(value + 1) > 255))
            {
                int newpos = jumpNextPos(caretPos);
                if (nextDecimalPos < text.length())
                    selectNextBlock(newpos);
                return newpos;
            }
            return caretPos;

        }
        catch (NumberFormatException e)
        {

            return caretPos;

        }

    }

    public boolean isMaxValue(int caretPos, KeyEvent key)
    {

        int lastDecimalPos = -1;

        int nextDecimalPos = 0;

        for (Iterator<Integer> i = delims.iterator(); i.hasNext(); )
        {

            int x = i.next().intValue();

            if (x < caretPos)
            {
                lastDecimalPos = x;

            }
            if (x > caretPos)
            {

                nextDecimalPos = x;

                break;

            }

        }

        if (lastDecimalPos >= nextDecimalPos)
        {
            nextDecimalPos = text.length();

        }
        String value = text.substring(lastDecimalPos + 1, nextDecimalPos);

        try
        {

            int loc = caretPos - lastDecimalPos - 1;

            if (loc < 0)
            {
                loc = 0;

            }
            StringBuffer tempBuffer = new StringBuffer(value);
            if (loc == tempBuffer.length())
            {
                tempBuffer.append(' ');
            }
            tempBuffer.setCharAt(loc, key.getKeyChar());
            //     tempBuffer.insert(loc, key.getKeyChar() );

            if (Integer.parseInt(tempBuffer.toString().trim()) > 255)
            {

                return false;

            }
            return true;

        }
        catch (NumberFormatException e)
        {

            return true;

        }

    }

    private boolean isEmpty(int caretPos)
    {
        int lastDecimalPos = -1;

        int nextDecimalPos = 0;

        for (Iterator<Integer> i = delims.iterator(); i.hasNext(); )
        {

            int x = i.next().intValue();

            if (x < caretPos)
            {
                lastDecimalPos = x;

            }
            if (x > caretPos)
            {

                nextDecimalPos = x;

                break;

            }

        }

        if (lastDecimalPos >= nextDecimalPos)
        {
            nextDecimalPos = text.length();

        }
        String value = text.substring(lastDecimalPos + 1, nextDecimalPos);

        if (value.trim().length() == 0)
        {
            return true;
        }
        return false;
    }

    private boolean isSelected(int caretPos)
    {
        return ( getSelectedText() != null &&
                 caretPos >= getSelectionStart() &&
                 caretPos <= getSelectionEnd() );
    }

    /**
     * Get property change support of the JTextField.
     * @return java.beans.PropertyChangeSupport
     */
    public PropertyChangeSupport getPcs()
    {
        if (pcs == null)
        {
            pcs = new PropertyChangeSupport(this);
        }
        return pcs;
    }
    
    @Override
    public void addPropertyChangeListener(final PropertyChangeListener listener)
    {
        super.addPropertyChangeListener(listener);
        getPcs().addPropertyChangeListener(listener);
    }

    @Override
    public void removePropertyChangeListener(final PropertyChangeListener listener)
    {
        super.removePropertyChangeListener(listener);
        getPcs().removePropertyChangeListener(listener);
    }
    
    @Override
    public void addPropertyChangeListener(final String propertyName, final PropertyChangeListener listener)
    {
        super.addPropertyChangeListener(propertyName, listener);
        getPcs().addPropertyChangeListener(propertyName, listener);
    }
    
    @Override
    public void removePropertyChangeListener(final String propertyName, final PropertyChangeListener listener)
    {
        super.removePropertyChangeListener(propertyName, listener);
        getPcs().removePropertyChangeListener(propertyName, listener);
    }
    
	/**
	 * Called when the content of the editor changed
	 */
	private void contentChanged()
	{
		String text = super.getText();
		putClientProperty(IPEditor.TEXT_PROPERTY, text);
	}

	private class ParseIPDocumentListener implements DocumentListener
	{
		/**
		 * Gives notification that there was an insert into the document. The
		 * range given by the DocumentEvent bounds the freshly inserted region.
		 * 
		 * @param e
		 *            the document event
		 */
		public void insertUpdate(DocumentEvent e)
		{
			contentChanged();
		}

		/**
		 * Gives notification that a portion of the document has been removed.
		 * The range is given in terms of what the view last saw (that is,
		 * before updating sticky positions).
		 * 
		 * @param e
		 *            the document event
		 */
		public void removeUpdate(DocumentEvent e)
		{
			contentChanged();
		}

		/**
		 * Gives notification that an attribute or set of attributes changed.
		 * 
		 * Called when the style of some of the text in the listened-to document changes. 
		 * This sort of event is fired only from a StyledDocument
		 *  — a PlainDocument does not fire these events.
		 * @param e
		 *            the document event
		 */
		public void changedUpdate(DocumentEvent e)
		{
			contentChanged();
		}
	}
}
